/*
 * Copyright (c) 2024 Shenzhen Kaihong Digital Industry Development Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include <pthread.h>
#include "sle_ssap_server_hdi.h"
#include "sle_ssap_config.h"
#include "sle_ssap_server_config.h"
#include "sle_hal_errcode.h"
#include "sle_hilog.h"
#include "sle_ssap_server.h"
#include "sle_callback_adapter.h"
#include <time.h>
#include <sched.h>
extern uint16_t SLE_CONNECT_UPDATE_INTERVAL_HDI;
extern uint8_t gle_tx_acb_data_num_get(void);
extern uint64_t sle_clock_gettime_us_kh_lite(void);
pthread_mutex_t send_mutex_server;

SleHdiErrorCode SleHdiAdapterSsapsRegisterServer(const SleUuid *appUuid, uint8_t *serverId)
{
    SLE_ASSERT_AND_RETURN_RET(appUuid != NULL, SLE_HAL_ERR_INVALID_PARAM);
    SLE_ASSERT_AND_RETURN_RET(serverId != NULL, SLE_HAL_ERR_INVALID_PARAM);
    SleHdiErrorCode ret = SLE_HDI_ERRCODE_FAIL;
    ret = ssaps_register_server((sle_uuid_t*)appUuid, serverId);
    return ret;
}

SleHdiErrorCode SleHdiAdapterSsapsUnregisterServer(uint8_t serverId)
{
    SleHdiErrorCode ret = SLE_HDI_ERRCODE_FAIL;
    ret = ssaps_unregister_server(serverId);
    return ret;
}

SleHdiErrorCode SleHdiAdapterSsapsAddService(uint8_t serverId, const SleUuid *ServiceUuid, bool IsPrimary, uint16_t *handle)
{
    SLE_ASSERT_AND_RETURN_RET(ServiceUuid != NULL, SLE_HAL_ERR_INVALID_PARAM);
    SLE_ASSERT_AND_RETURN_RET(handle != NULL, SLE_HAL_ERR_INVALID_PARAM);
    SleHdiErrorCode ret = SLE_HDI_ERRCODE_FAIL;
    ret = ssaps_add_service_sync(serverId, (sle_uuid_t*)ServiceUuid, IsPrimary, handle);
    return ret;
}

SleHdiErrorCode SleHdiAdapterSsapsAddProperty(uint8_t serverId, uint16_t serviceHandle, const SsapsPropertyParam *property,
    uint16_t *handle)
{
    SLE_ASSERT_AND_RETURN_RET(property != NULL, SLE_HAL_ERR_INVALID_PARAM);
    SLE_ASSERT_AND_RETURN_RET(handle != NULL, SLE_HAL_ERR_INVALID_PARAM);
    ssaps_property_info_t property_sdk = {
        .permissions = (uint16_t)property->permissions,
        .operate_indication = (uint32_t)property->opIndication,
        .value_len = property->valueLen,
        .value = property->value,
    };
    memcpy(property_sdk.uuid.uuid, property->uuid.uuid, sizeof(property->uuid.uuid));
    property_sdk.uuid.len = property->uuid.len;
    SleHdiErrorCode ret = SLE_HDI_ERRCODE_FAIL;
    ret = ssaps_add_property_sync(serverId, serviceHandle, &property_sdk, handle);
    return ret;
}

SleHdiErrorCode SleHdiAdapterSsapsAddDescriptor(uint8_t serverId, uint16_t serviceHandle, uint16_t propertyHandle,
    const SsapsDescriptorParam *descriptor, uint16_t *handle)
{
    SLE_ASSERT_AND_RETURN_RET(descriptor != NULL, SLE_HAL_ERR_INVALID_PARAM);
    SLE_ASSERT_AND_RETURN_RET(handle != NULL, SLE_HAL_ERR_INVALID_PARAM);
    SleHdiErrorCode ret = SLE_HDI_ERRCODE_FAIL;
    ssaps_desc_info_t descriptor_sdk = {
        .permissions = (uint16_t)descriptor->permissions,
        .operate_indication = (uint32_t)descriptor->operateInd,
        .type = (uint8_t)descriptor->type,
        .value_len = descriptor->valueLen,
        .value = descriptor->value,
    };
    memcpy(&(descriptor_sdk.uuid), &(descriptor->uuid), sizeof(sle_uuid_t));
    ret = ssaps_add_descriptor_sync(serverId, serviceHandle, propertyHandle, &descriptor_sdk);
    return ret;
}

SleHdiErrorCode SleHdiAdapterSsapsStartService(uint8_t serverId, uint16_t serviceHandle)
{
    SleHdiErrorCode ret = SLE_HDI_ERRCODE_FAIL;
    ret = ssaps_start_service(serverId, serviceHandle);
    return ret;
}

SleHdiErrorCode SleHdiAdapterSsapsDeleteAllServices(uint8_t serverId)
{
    SleHdiErrorCode ret = SLE_HDI_ERRCODE_FAIL;
    ret = ssaps_delete_all_services(serverId);
    return ret;
}

SleHdiErrorCode SleHdiAdapterSsapsSendResponse(uint8_t serverId, uint16_t connectId, const SsapsSendRspParam *param)
{
    SLE_ASSERT_AND_RETURN_RET(param != NULL, SLE_HAL_ERR_INVALID_PARAM);
    SleHdiErrorCode ret = SLE_HDI_ERRCODE_FAIL;
    ssaps_send_rsp_t param_sdk = {
        .request_id = param->requestId,
        .status = (uint8_t)param->status,
        .value_len = param->valueLen,
        .value = param->value,
    };
    ret = ssaps_send_response(serverId, connectId, &param_sdk);
    return ret;
}

static SleHdiErrorCode sle_notify_indicate_sync(uint8_t serverId, uint16_t connectId, ssaps_ntf_ind_t *param)
{
    SleHdiErrorCode ret = -1;
    int sflag = 0;
    uint64_t kht_before_get_jiffies = 0, kht_after_get_jiffies = 0;
    uint64_t after_us = 0;
    uint32_t wait_min_time_us = (SLE_CONNECT_UPDATE_INTERVAL_HDI * 125);  // 最少等待1个发送间隔(可以是连接间隔)
    int retry = 2000; // 最多等待2000个连接间隔时间
    kht_before_get_jiffies = sle_clock_gettime_us_kh_lite();
    after_us = kht_before_get_jiffies + wait_min_time_us; // 防止溢出回卷, 等待超时时间

    while (1) {
        if (sflag == 0 && gle_tx_acb_data_num_get() > 0) {
            ret = ssaps_notify_indicate(serverId, connectId, param);
            sflag = 1;
        }

        kht_after_get_jiffies = sle_clock_gettime_us_kh_lite();
        if ((int)(kht_after_get_jiffies - after_us) < 0) { // 这里至少等待1个连接间隔(或发送间隔)
            sched_yield();
        } else {
            if (sflag == 0 && (--retry) > 0) {
                after_us += wait_min_time_us; // 没有发出去包的话 这里要继续等待下一个连接间隔(或发送间隔)
                sched_yield();
                continue;
            }
            // 超过最大等待时间,没有发送出去, 失败退出
            // 或者发送出去了, 成功返回
            break;
        }
    }
    return ret;
}

SleHdiErrorCode SleHdiAdapterSsapsNotifyIndicate(uint8_t serverId, uint16_t connectId, const SsapsNotifyParam *param)
{
    SLE_ASSERT_AND_RETURN_RET(param != NULL, SLE_HAL_ERR_INVALID_PARAM);
    pthread_mutex_lock(&send_mutex_server);
    SleHdiErrorCode ret = SLE_HDI_ERRCODE_FAIL;
    ssaps_ntf_ind_t param_sdk = {
        .handle = param->handle,
        .type = (uint8_t)param->type,
        .value_len = param->valueLen,
        .value = param->value,
    };
    ret = sle_notify_indicate_sync(serverId, connectId, &param_sdk);
    pthread_mutex_unlock(&send_mutex_server);
    return ret;
}

SleHdiErrorCode SleHdiAdapterSsapsNotifyIndicateByUuid(uint8_t serverId, uint16_t connectId, const SsapsNotyfyByUuidParam *param)
{
    SLE_ASSERT_AND_RETURN_RET(param != NULL, SLE_HAL_ERR_INVALID_PARAM);
    SleHdiErrorCode ret = SLE_HDI_ERRCODE_FAIL;
    ssaps_ntf_ind_by_uuid_t param_sdk = {
        .start_handle = param->startHandle,
        .end_handle = param->endHandle,
        .type = (uint8_t)param->type,
        .value_len = param->valueLen,
        .value = param->value,
    };
    memcpy(&(param_sdk.uuid), &(param->uuid), sizeof(sle_uuid_t));
    ret = ssaps_notify_indicate_by_uuid(serverId, connectId, &param_sdk);
    return ret;
}

SleHdiErrorCode SleHdiAdapterSsapsSetInfo(uint8_t serverId, const SsapMtuInfo *info)
{
    SLE_ASSERT_AND_RETURN_RET(info != NULL, SLE_HAL_ERR_INVALID_PARAM);
    SleHdiErrorCode ret = SLE_HDI_ERRCODE_FAIL;
    ret = ssaps_set_info(serverId, (ssap_exchange_info_t*)info);
    return ret;
}

SleHdiErrorCode SleHdiAdapterSsapsRegisterCallbacks(SleSsapsHdiCallbacks *callbacks)
{
    SLE_ASSERT_AND_RETURN_RET_LOG(callbacks != NULL, SLE_HAL_ERR_INVALID_PARAM, "SleHdiSsapsRegisterCallbacks");
    SleHdiErrorCode ret = SLE_HDI_ERRCODE_FAIL;
    ret = RegisterSsapsCallbackAdapter(callbacks);
    return ret;
}

SleHdiErrorCode GetSleSsapsHdiOpts(SleSsapsHdiOpts *ssapsOpts)
{
    SLE_ASSERT_AND_RETURN_RET_LOG(ssapsOpts != NULL, SLE_HAL_ERR_INVALID_PARAM, "GetSleSsapsHdiOpts");
    ssapsOpts->registerServer = SleHdiAdapterSsapsRegisterServer;
    ssapsOpts->unregisterServer = SleHdiAdapterSsapsUnregisterServer;
    ssapsOpts->addService = SleHdiAdapterSsapsAddService;
    ssapsOpts->addProperty = SleHdiAdapterSsapsAddProperty;
    ssapsOpts->addDescriptor = SleHdiAdapterSsapsAddDescriptor;
    ssapsOpts->startService = SleHdiAdapterSsapsStartService;
    ssapsOpts->deleteAllServices = SleHdiAdapterSsapsDeleteAllServices;
    ssapsOpts->sendResponse = SleHdiAdapterSsapsSendResponse;
    ssapsOpts->sendNotifyIndicate = SleHdiAdapterSsapsNotifyIndicate;
    ssapsOpts->sendNotifyIndicateByUuid = SleHdiAdapterSsapsNotifyIndicateByUuid;
    ssapsOpts->setServerMtuInfo = SleHdiAdapterSsapsSetInfo;
    ssapsOpts->registerServerCbks = SleHdiAdapterSsapsRegisterCallbacks;
    return SLE_HDI_ERRCODE_SUCC;
}